今天要做的是操作 Canvas,並做出類似小畫家的效果,隨意在畫布上作畫。其實在做這一天內容前我沒有接觸過 Canvas,只好臨時抱佛腳趕快學一些基本的東西,還好還是做出來了...
完成作品:Fun with HTML5 Canvas、程式碼
首先要先知道如何在 Canvas 畫出線條、更改樣式!
在 HTML 創建了一個 canvas
tag 之後就可以把注意力轉移到 JS 了,首先先做一些基本設定
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
canvas.width = innerWidth;
canvas.height = innerHeight;
由於我們要知道滑鼠當下位置的座標來當作劃線的起點,所以需要設定監聽事件來得知當按下滑鼠左鍵時的座標
// 記錄最後的座標
let lastX = 0;
let lastY = 0;
canvas.addEventListener('mousedown', function(e) {
lastX = e.offsetX;
lastY = e.offsetY;
});
規劃想法是記錄最後一點後每次都依 lastX
、lastY
的座標位置為畫線起點,而我希望當按下滑鼠 + 移動滑鼠時會開始畫線,所以要再設定一個監聽事件(mousemove)以及畫線的函式
canvas.addEventListener('mousemove', draw);
function draw(e) {
// 開始畫線
ctx.beginPath();
ctx.moveTo(lastX, lastY);
ctx.lineTo(e.x, e.y);
ctx.stroke();
// 紀錄最後座標
lastX = e.x;
lastY = e.y;
}
可以看到當滑鼠移動時 lastX
與 lastY
是隨時在更新並劃出新的直線的,但畫面上看起來就像是真的在畫畫一樣。
接著要設定當滑鼠移動時,線條的粗細可以變大 > 變小 > 再變大的迴圈;同時不停的更改顏色
這裡介紹的方法是我之前沒有使用過的 hsl
調色方法,共有三個參數如下:hsl(色相角度但不加單位0~360, 色彩飽和度0~100%, 色彩亮度0~100%)
為了隨時更改顏色,我們先將變數 hue
初始值設定為 0,並隨著滑鼠移動不停變更數字,直到 360 後歸零重算
let hue = 0;
function draw(e) {
// 開始畫線
ctx.strokeStyle = `hsl(${hue}, 100%, 50%)`;
ctx.beginPath();
ctx.moveTo(lastX, lastY);
ctx.lineTo(e.x, e.y);
ctx.stroke();
// 紀錄最後座標
lastX = e.x;
lastY = e.y;
// 改變顏色
if (hue >= 360) {
hue = 0;
} else if (hue > -1) {
hue++;
}
}
判別很簡單,當 hue
大於 360 後歸零,其餘狀況加 1,並記得改變線條顏色 ctx.strokeStyle = 'hsl(${hue}, 100%, 50%)'
類似於改變顏色,一開始會先給寬度初始值,但不同的是當到達一定程度時,希望寬度能隨著移動減少寬度而不是歸零,並在等於 0 時變成增加寬度
let width = 100;
let widthVelocity = 1;
function draw(e) {
// 開始畫線
ctx.lineWidth = width;
ctx.strokeStyle = `hsl(${hue}, 100%, 50%)`;
ctx.beginPath();
ctx.moveTo(lastX, lastY);
ctx.lineTo(e.x, e.y);
ctx.stroke();
// 紀錄最後座標
lastX = e.x;
lastY = e.y;
// 改變顏色
if (hue >= 360) {
hue = 0;
} else if (hue > -1) {
hue++;
}
// 改變粗細
if (width <= 1 || width > 100) {
widthVelocity = -widthVelocity;
}
width += widthVelocity;
}
這裡解釋一下,寬度一開始先設定 100,並期望寬度隨著每次移動而減少,所以變數 widthVelocity
就是在控制減少的變因。
當寬度加超過 100 時,將 widthVelocity
轉為 -1 就能做到反轉的效果,並隨著寬度減少至 1 時更改成 1,此時寬度變成增加了。
現在可以作畫了,但卻無法結束啊!所以需要再設定監聽事件,當 mouseup
發生或是滑鼠移出畫面(mouseleave)時停止 draw()
的功能。
這裡的做法是設定變數 let isDrawing = false
來判定目前是否應該執行 draw()
,並在上述兩種狀況以外時(也就是按下按鍵時)將狀態改成 true
let isDrawing = false;
canvas.addEventListener('mousedown', function(e) {
isDrawing = true;
lastX = e.offsetX;
lastY = e.offsetY;
});
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('mouseup', function() {
isDrawing = false;
});
canvas.addEventListener('mouseleave', function() {
isDrawing = false;
});
最後,線條看起來其實不太圓滑,所以再改變一些屬性點綴一下:
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
到這裡就大功告成了!太好了!